package com.clock.shiro.config;


import com.clock.shiro.AccountRealm;
import com.clock.shiro.JwtFilter;
import com.clock.shiro.ManagerFilter;
import com.clock.shiro.TokenCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro配置
 */
@Configuration
public class ShiroConfig {

    /**
     * 功能描述: 注入realm进行安全管理
     *
     * @param accountRealm
     * @return org.apache.shiro.web.mgt.DefaultWebSecurityManager
     */
    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(AccountRealm accountRealm, RedisProperties redisProperties, TokenCredentialsMatcher tokenCredentialsMatcher) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //开启认证缓存
        /*accountRealm.setAuthenticationCachingEnabled(true);
        accountRealm.setAuthenticationCacheName("authenticationCache");*/
        accountRealm.setCredentialsMatcher(tokenCredentialsMatcher);
        securityManager.setRealm(accountRealm);

        //关闭shiro自带的session存放token功能
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);

        //使用redis设置自定义缓存token
        securityManager.setCacheManager(redisCacheManager(redisProperties));
        return securityManager;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);

        Map<String, String> filterMap = new LinkedHashMap<>();
        //给登录和注册放行
        filterMap.put("/account/login", "anon");
        filterMap.put("/account/register", "anon");
        filterMap.put("/account/checkUserInf", "anon");

        filterMap.put("/doc.html", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/v2/**", "anon");
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/csrf","anon");

        //给游客放行
        filterMap.put("/discussPost/normalPosts","anon");
        filterMap.put("/discussPost/detail/**","anon");
        //filterMap.put("/**","anon");

        //其他特殊权限的路径
        //样例 ： filterMap.put("路径","权限");
        filterMap.put("/managerUser/**","jwt,roles[顶级管理]");
        filterMap.put("/chicken/addChicken","jwt,managers[顶级管理,管理]");
        filterMap.put("/chicken/batchAddChicken","jwt,managers[顶级管理,管理]");

        //jwt过滤 所有请求都需要过一个shiro的认证
        filterMap.put("/**", "jwt,authc");

        // filterMap.put("/**","anon");  //打开全部放行

        Map<String, Filter> filters = new HashMap<>();
        filters.put("jwt", new JwtFilter());
        filters.put("managers",new ManagerFilter());


        shiroFilter.setFilters(filters);
        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }


    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisCacheManager redisCacheManager(RedisProperties redisProperties) {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager(redisProperties));

        //配置用户权限缓存的尾缀
        redisCacheManager.setPrincipalIdFieldName("userId");
        //用户权限信息缓存时间
        redisCacheManager.setExpire(3600);
        return redisCacheManager;
    }

    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    @Bean
    public RedisManager redisManager(RedisProperties redisProperties) {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisProperties.getHost());
        redisManager.setPort(redisProperties.getPort());
        redisManager.setTimeout(0);
        if (!StringUtils.isEmpty(redisProperties.getPassword())) {
            redisManager.setPassword(redisProperties.getPassword());
        }
        return redisManager;
    }



    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    // 开启注解代理
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager((org.apache.shiro.mgt.SecurityManager) securityManager);
        return advisor;
    }

}
